package edu.bbu.cshu.wmpc.plagiarism;

import java.sql.Connection;
import java.util.ArrayList;

import org.apache.log4j.Level;

import edu.bbu.cshu.wmpc.checking.PerformAllTests;
import edu.bbu.cshu.wmpc.core.FileTypes;
import edu.bbu.cshu.wmpc.core.LevelTypes;
import edu.bbu.cshu.wmpc.core.SourceCodeWmpc;
import edu.bbu.cshu.wmpc.core.TestTypes;
import edu.bbu.cshu.wmpc.dao.DAOFactory;
import edu.bbu.cshu.wmpc.dao.jdbc.ConnectionManager;
import edu.bbu.cshu.wmpc.loggin.EventLogger;
/**
 * <ul>
 * <li><b><i>PlagiarismTest</i></b></li>
 * <li style="list-style: none;"></li>
 * <li style="list-style: none;">
 * Enumeration that is the main class of the project. Through this all communication with an outside project can be achieved. All functions that ensure information sending and receiving are implemented here. 
 * 
 * @author WMPC team
 * </li>
 * </ul>
 */ 
public enum PlagiarismTest {
	/**
	 * <ul>
	 * <li><b><i>INSTANCE</i></b></li>
	 * <li style="list-style: none;"></li>
	 * <li style="list-style: none;">
	 * Ensures that only a single instance of the enumeration exists.
	 * 
	 * </li>
	 * </ul>
	 */
	INCTANCE;
	/**
	 * <ul style="margin-top: 24px;">
	 * <li><b><i>configureConnection</i></b></li>
	 * <li style="list-style: none;"></li>
	 * <li style="list-style: none;">
	 * <p style="margin-left: 7px;">{@code public void configureConnection({@link String} server, int port, {@link String} database, {@link String} usr, {@link String} pwd)}</p>
	 * <br>	
	 * Sets the name of the {@code server}, the {@code port} number, {@code database} name, {@code user name} and {@code password} required to open a {@link Connection}. 
	 * 
	 * @param server   - name of the {@code server}
	 * @param port	   - {@code port} number
	 * @param database - name of the {@code database}
	 * @param usr	   - {@code user name}
	 * @param pwd	   - {@code password}
	 * </li>
	 * </ul>
	 */
	public void configureConnection(String server, int port, String database, String usr, String pwd) {
		ConnectionManager.INSTANCE.configureConnection(server, port, database, usr, pwd);
	}
	/**
	 * <ul style="margin-top: 24px;">
	 * <li><b><i>configureLogger</i></b></li>
	 * <li style="list-style: none;"></li>
	 * <li style="list-style: none;">
	 * <p style="margin-left: 7px;">{@code public void configureLogger(}{@link String} {@code URL)}</p>
	 * <br>	
	 * Sets the ULR of the properties used by the {@code EventLogger}.
	 * 
	 * @param URL - {@code String} specifying the location of the log file
	 * </li>
	 * </ul>
	 */
	public void configureLogger(String URL) {
		EventLogger.INSTANCE.configureLogger(URL);
	}
	/**
	 * <ul style="margin-top: 24px;">
	 * <li><b><i>writeToLog</i></b></li>
	 * <li style="list-style: none;"></li>
	 * <li style="list-style: none;">
	 * <p style="margin-left: 7px;">{@code public void writeToLog(}{@link Level} {@code lvl,} {@link String} {@code msg)}</p>
	 * <br>	
	 * Writes an entry in the log file, taking into account the specified {@code level}. 
	 * 
	 * @param lvl - {@code Level} of the massage 
	 * @param msg - message to be logged
	 * </li>
	 * </ul>
	 */
	public void writeToLog(Level lvl, String msg) {
		EventLogger.INSTANCE.writeToLog(lvl, msg);
	}
	/**
	 * <ul style="margin-top: 24px;">
	 * <li><b><i>getTestTypes</i></b></li>
	 * <li style="list-style: none;"></li>
	 * <li style="list-style: none;">
	 * <p style="margin-left: 7px;">{@code public }{@link ArrayList}<{@link String}> {@code getTestTypes()}</p>
	 * <br>	
	 * Returns all the names of the {@link TestTypes} converted into {@code String}, containing the full name of the test.
	 * 
	 * @return an {@code ArrayList<String>} containing the names of all the {@code TestTypes}
	 * </li>
	 * </ul>
	 */
	public ArrayList<String> getTestTypes() {
		TestTypes[] list = TestTypes.values();
		ArrayList<String> str = new ArrayList<String>();

		for (int i = 0; i < list.length; i++) {
			switch (list[i]) {
				case COSINE: str.add("Cosine Similarity"); break;
				case DICE: str.add("Dice Coefficient"); break;
				case LEVENSHTEIN: str.add("Levenshtein Distance"); break;
			}
		} 
		
		return str;
	}
	/**
	 * <ul style="margin-top: 24px;">
	 * <li><b><i>getLevelTypes</i></b></li>
	 * <li style="list-style: none;"></li>
	 * <li style="list-style: none;">
	 * <p style="margin-left: 7px;">{@code public }{@link ArrayList}<{@link String}> {@code getLevelTypes()}</p>
	 * <br>	
	 * Returns all the names of the {@link LevelTypes} converted into {@code String}, with only first letter being upper case.
	 * 
	 * @return an {@code ArrayList<String>} containing the names of all the {@code LevelTypes}
	 * </li>
	 * </ul>
	 */
	public ArrayList<String> getLevelTypes() {
		LevelTypes[] list = LevelTypes.values();
		ArrayList<String> str = new ArrayList<String>();
		
		String tmp;
		for (int i = 0; i < list.length; i++){
			tmp = list[i].toString();
			str.add("" + tmp.charAt(0) + tmp.substring(1, tmp.length()).toLowerCase());
		}
		
		return str;
	}
	/**
	 * <ul style="margin-top: 24px;">
	 * <li><b><i>getFileTypes</i></b></li>
	 * <li style="list-style: none;"></li>
	 * <li style="list-style: none;">
	 * <p style="margin-left: 7px;">{@code public }{@link ArrayList}<{@link String}> {@code getFileTypes()}</p>
	 * <br>	
	 * Returns all the names of the {@link FileTypes} converted into {@code String}, with only first letter being upper case.
	 * 
	 * @return an {@code ArrayList<String>} containing the names of all the {@code FileTypes}
	 * </li>
	 * </ul>
	 */
	public ArrayList<String> getFileTypes() {
		FileTypes[] list = FileTypes.values();
		ArrayList<String> str = new ArrayList<String>();
		
		String tmp;
		for (int i = 0; i < list.length; i++){
			tmp = list[i].toString();
			str.add("" + tmp.charAt(0) + tmp.substring(1, tmp.length()).toLowerCase());
		}
		
		return str;
	}
	/**
	 * <ul style="margin-top: 24px;">
	 * <li><b><i>getFileInfo</i></b></li>
	 * <li style="list-style: none;"></li>
	 * <li style="list-style: none;">
	 * <p style="margin-left: 7px;">{@code public} {@link ArrayList}<{@link String}> {@code getFileInfo(}{@link String} {@code type) throws} {@link Exception}</p>
	 * <br>	
	 * Returns the group names of files which {@code type} was been specified. Files are being grouped according to the assignment {@code id} and student {@code id}. 
	 * 
	 * @param type - {@code type} of file to return information about 
	 * @return     {@code ArrayList<String>} containing the file group names
	 * @throws	   if any error occurred while trying to return information about the file
	 * </li>
	 * </ul>
	 */
	public ArrayList<String> getFileInfo(String type) throws Exception{
		return DAOFactory.getInstance().getCodeDAO().getAllFileInfos(FileTypes.valueOf(type.toUpperCase()));
	}
	/**
	 * <ul style="margin-top: 24px;">
	 * <li><b><i>getResults</i></b></li>
	 * <li style="list-style: none;"></li>
	 * <li style="list-style: none;">
	 * <p style="margin-left: 7px;">{@code public} {@link ArrayList}<{@link Object}> {@code getResults(}{@link String} {@code group1,} {@link String} {@code group2}, {@link ArrayList}<{@link String}> {@code tests,} {@link String} {@code level,} {@link String} {@code type) throws} {@link Exception}</p>
	 * <br>	
	 * Performs a group of {@code tests} with specified roughness {@code level}, between two {@link SourceCodeWmpc} {@code Objects}, specified by {@code group1} and {@code group2}. {@code Type} of the {@code SourceCodeWmpc Object} is also specified. 
	 * 
	 * @param group1 - {@code String} group name of first {@code SourceCodeWmpc Object}
	 * @param group2 - {@code String} group name of second {@code SourceCodeWmpc Object}
	 * @param tests  - {@code ArrayList<String>} containing names of tests to be performed 
	 * @param level  - {@code LevelTypes} specifying the roughness of the {@code tests}
	 * @param type	 - {@code FileTypes} specifying the type of file on which {@code tests} are to be performed   
	 * @return		 an {@code ArrayList<Object>} containing all the test results
	 * @throws 		 if any error occurred while trying to execute tests 
	 * </li>
	 * </ul>
	 */
	@SuppressWarnings("unchecked")
	public ArrayList<Object> getResults(String group1, String group2, ArrayList<String> tests, String level, String type) throws Exception{
		SourceCodeWmpc sc1 = DAOFactory.getInstance().getCodeDAO().getAllFileContents(group1, FileTypes.valueOf(type.toUpperCase()));
		SourceCodeWmpc sc2 = DAOFactory.getInstance().getCodeDAO().getAllFileContents(group2, FileTypes.valueOf(type.toUpperCase()));
		
		ArrayList<TestTypes> list = new ArrayList<TestTypes>();
		
		for (int i = 0; i < tests.size(); i++) {
			switch (tests.get(i)) {
				case "Cosine Similarity": list.add(TestTypes.COSINE); break;
				case "Dice Coefficient": list.add(TestTypes.DICE); break;
				case "Levenshtein Distance": list.add(TestTypes.LEVENSHTEIN); break;
			}
		}
		
		PerformAllTests.INSTANCE.setTestsToDo(list);
		ArrayList<Object> testResults = PerformAllTests.INSTANCE.performTests(LevelTypes.valueOf(level.toUpperCase()), sc1, sc2);
		
		ArrayList<Object> results = new ArrayList<Object>();
		ArrayList<Integer> linesNum = null;
		ArrayList<String> lines = null; 
		
		for (int i = 0; i < testResults.size(); i++) {
			results.add(testResults.get(i));
			linesNum = (ArrayList<Integer>) testResults.get(i+1);
			results.add(linesNum);
			
			lines = new ArrayList<String>();
			for (int j = 0; j < linesNum.size(); j++) {
				lines.add(sc1.getFromOriginal(linesNum.get(j)));
				lines.add(sc2.getFromOriginal(linesNum.get(j+1)));
				j++;
			}
			
			results.add(lines);
			i++;
		}
		results.add(sc1.getContentIndexes());
		results.add(sc2.getContentIndexes());
		
		return results;
	}
}
